package edu.kit.csl.pisa.models;

/*
This file is part of the PISA Alignment Tool.

Copyright (C) 2013
Karlsruhe Institute of Technology
Cognitive Systems Lab (CSL)
Felix Stahlberg

PISA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PISA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PISA. If not, see <http://www.gnu.org/licenses/>.
*/

import java.util.Arrays;

import edu.kit.csl.pisa.datatypes.AlignmentPosition;
import edu.kit.csl.pisa.datatypes.Dictionary;
import edu.kit.csl.pisa.datatypes.SentenceAlignment;

/**
 * This model should not be used in productive setting, but in testing
 * environments like in JUnits tests. This model could also used for
 * educational purposes or as sample alignment model.
 * This alignment model just knows lexical translation parameters. It is
 * similar to IBM Model 1, since
 * P(a,f|e) = \Pi_i t(f|e_a_i)
 */
public class SimpleModel extends AlignmentModel {

	/*
	 * Log probabilities of lexical translations.
	 */
	private double[][] t;
	
	/*
	 * New t parameter when collecting fractional counts.
	 */
	private double[][] newT;
	
	/**
	 * Uniform distribution for lexical translation.
	 * {@inheritDoc}
	 */
	public SimpleModel(String name) {
		super(name);
		distributeUniformly();
	}

	/**
	 * Sums up lexical translation log probabilities.
	 * {@inheritDoc} 
	 */
	@Override
	public double calculateAlignmentProbability(SentenceAlignment a) {
		double p = 0;
		for (AlignmentPosition pos : a) {
			// Sum up because t contains log probabilities
			p += t[pos.getSourceWord()][pos.getTargetPhoneme()];
		}
		return p;
	}
	
	/**
	 * Get the lexical translation table. The first dimension stores source 
	 * word-ids, and the second dimension stores target word-ids.
	 * 
	 * @return the lexical translation table t
	 */
	public double[][] getParameterT() {
		return t;
	}

	/* (non-Javadoc)
	 * @see edu.kit.csl.pisa.models.AlignmentModel#initializeFractionalCounts()
	 */
	@Override
	public void initializeFractionalCounts() {
		newT = new double[t.length][t[0].length];
	}
	
	/* (non-Javadoc)
	 * @see edu.kit.csl.pisa.models.AlignmentModel#writeBackFractionalCounts()
	 */
	@Override
	public void writeBackFractionalCounts() {
		// Normalize
		for (double[] row : newT) {
			normalize(row);
		}
		t = newT;
		newT = null;
	}
	
	/**
	 * Writes the collected fractional count with given weight to newT.
	 * {@inheritDoc}
	 */
	@Override
	public void aggregateFractionalCount(SentenceAlignment a,
			double weight) {
		synchronized (newT) {
			for (AlignmentPosition pos : a) {
				newT[pos.getSourceWord()][pos.getTargetPhoneme()] += 
						weight;
			}
		}
	}
	
	/**
	 * Import lexical translation table from other models. Only import from
	 * {@link Model3} (IBM Model3 from GIZA++) is implemented.
	 * 
	 * @param srcModel should be a {@link Model3} instance. Import only lexical
	 * 		translation table.
	 * @throws UnsupportedOperationException if srcModel is not a 
	 * 				{@link Model3} instance 
	 */
	@Override
	public void importModelParameters(AlignmentModel srcModel)
			throws IllegalArgumentException {
		if (srcModel instanceof Model3) {
			t = ((Model3) srcModel).getParameterT();
		}
		throw new IllegalArgumentException("Import is only implemented"
				+ " for IBM Model 3.");
	}
	
	/*
	 * Distribute lexical translation probabilities uniformly.
	 */
	private void distributeUniformly() {
		final int trgtSize = 
				Dictionary.getSingleton(Dictionary.TRGT_DICT).size();
		t = new double	[Dictionary.getSingleton(Dictionary.SRC_DICT).size()]
						[trgtSize];
		final double uniProb = Math.log(1f / trgtSize);
		for (double[] a1 : t) {
			Arrays.fill(a1, uniProb);
		}
	}

	/**
	 * The only model parameter is <code>t</code>.
	 * {@inheritDoc}
	 */
	@Override
	public void dumpToFilesystem(String prefix, String postfix) {
		this.dumpParameter(prefix + "t" + postfix, t);
		this.dumpParameter(prefix + "actual.t" + postfix, t, new Dictionary[]{
			Dictionary.getSingleton(Dictionary.SRC_DICT),
			Dictionary.getSingleton(Dictionary.TRGT_DICT)
		});
	}
}
